package gbench.appdemo.crawler.junit.jdbc;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.PostingsEnum;
import org.apache.lucene.search.DocIdSetIterator;
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import gbench.appdemo.crawler.srch.JdbcSrchApplication;
import gbench.appdemo.crawler.srch.JdbcSrchApplication.JdbcSrchEngine;
import gbench.common.fs.FileSystem;
import gbench.common.tree.LittleTree.IRecord;
import static gbench.common.tree.LittleTree.IRecord.*;

/**
 * 
 * @author gbench
 *
 */
public class JunitDataApp {
    
    /**
     * 简单的数据应用
     */
    @Test
    public void foo() {
        //索引数据库的路径
        final var path = jdbc.getIndexHome().getDirectory();
        System.out.println("index home:"+path);
        JdbcSrchApplication.traverse(path.toFile().getAbsolutePath(), File::delete);
        
        jdbc.initialize();
        //jdbc.setAnalyzer(new StandardAnalyzer());
        // 分词 演示
        Stream.of("中国人民是伟大的人民,春眠不觉晓".split(",")).forEach(line->{
            System.out.println("-----------"+line+"-----------");
            jdbc.analyze(line).forEach(e->{
                System.out.println(e);
            });// analyze
        });// forEach
        
        /**
         * 开始正式的启动 索引创建：索引 其实就是 结构化，或者说 对 研究对象进行勘测。
         * 就像地质 矿物勘测一样，我们需要 到各个省份，地区中 逐地区的 勘探，然后找出 各种矿物的 分布，储量情况。
         * 这个过程在信息检索领域 就被叫做 索引，其中的矿物 就是 Term, 矿物所在的地区 就是 待索引的 文本信息。
         * 特别需要注意，Analyzer 就是我们进行 矿物勘探的  勘探器，他会 把我们想要的 矿物质 (term) 给发现，并提取出来。
         */
        //jdb的数据操作
        jdbc.withTransaction(sess->{
            // JDBC 地址工程队 在 sayings。txt 的 勘探工作开始了。 
            FileSystem.utf8Read("sayings.txt", this.getClass(), br->{
                br.lines().filter(e->!e.matches("^\\s*$")).forEach(line->{ // 我们把sayings.txt 分成以line 为单位的分区
                    // matcher 就是在 line 分区中的底层的模式结构。我们的矿物就是 分布在这个 地层断带之中。
                    final var matcher = Pattern.compile("^\\s*(\\d+)[、]([^(—)]+)——(.+)$").matcher(line); // 
                    if(matcher.matches()) {
                        final var id = matcher.group(1); // 编号
                        final var text = matcher.group(2); // 文本
                        final var author = matcher.group(3); //  作者
                        
                        sess.sqladd(REC(// 制作一份 勘测档案(Document)
                            "id",id,
                            "$text",text, // 对于 text 地质带 进行 进行勘探，使用  analyzer 来给与 绘制 矿物分布图: (term 那些矿物, freq:多少,pos:深度,offset:埋藏位置),得出的结果会 姬路城 term到vector 
                            "author",author
                        ));// sqladd
                        
                    }//if
                });// forEach
            });// utf8Read
            sess.commit();
            sess.sqlgets(REC("id*","*")).forEach(e->{
                System.out.println(e);
            });
        });
        
        jdbc.uninitialize();
    }
    
    @Test
    public void bar() {
        jdbc.initialize();
        var reader = jdbc.getIndexReader();
        jdbc.setAnalyzer(new StandardAnalyzer());
        
        Stream.iterate(0, i -> i < reader.maxDoc(), i -> i + 1).forEach(id -> {// 以文档为单位进行存取
            try {
                final var fldName = reader.document(id).getField("text").stringValue();// 字段长度
                final var terms = reader.getTermVector(id, "text"); // 需要fieldType 设置对应属性来获取Term 向量
                final var termsEnum = terms.iterator();// 单词向量:
                var termref = termsEnum.next(); // term项结构
                var words = new LinkedList<IRecord>();
                int no_term = 0;// term计数器
                System.out.println("\n"+id+"#"+fldName);
                while (termref != null) { // 按照词项进行提取posting
                    final var postingEnums = termsEnum.postings(null,PostingsEnum.ALL);// termref 所统领的文档集合
                    var docid = DocIdSetIterator.NO_MORE_DOCS; // 先要调用 nextDoc 移动到1号doc
                    while(DocIdSetIterator.NO_MORE_DOCS!=(docid=postingEnums.nextDoc())) {// 遍历文档
                        int freq = postingEnums.freq();// 获取词文档中的频率
                        for(int i=0;i<freq;i++) { // 遍历position , position 是分词的在语句中的序号。
                            final var word = (REC(
                                "p-docid",docid, // 这个文档id 更像是 在postingEnums文档集合中的 序号。不是indexReader作为的docid
                                "#no_term",no_term, // term  项目的编号
                                "t-name", termref.utf8ToString(), // 名称
                                "t-length", termref.length, // byteref 的字节长度
                                "t-offset", termref.offset, // BytesRef 的第一位有效值的位置。
                                "p-pos",postingEnums.nextPosition(),// 是单词的序号,获取单词序号，但是当出现重复term的时候，后面的term就比省略了。
                                "p-payload", postingEnums.getPayload(), // 为何 没有payload 我没想明白
                                "p-freq", postingEnums.freq(),// 频率
                                "p-startOffset",postingEnums.startOffset(), // 开始位置的偏移
                                "p-endOffset",postingEnums.endOffset(), // 结束位置的偏移
                                "p-cost",postingEnums.cost() // 成本
                            )); // word
                            words.add(word);
                        }//for freq
                    }// while
                    
                    termref = termsEnum.next();// 提取下一个单词
                    no_term++;
                } // while
                words.stream().sorted((a,b)->a.i4("p-pos")-b.i4("p-pos")).forEach(word->{
                    System.out.println(word);
                });
                
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        
        jdbc.uninitialize();
    }
    
    public String indexHome = "indexes";// 索引文件的路径
    public String corpusHome = "C:\\Users\\gbench\\Desktop\\中国笔记\\逻辑词汇";// 语料库的词汇目录
    public String snapHome = "D:\\sliced\\tmp\\crawlersnap";// 快照文件根目录
    final JdbcSrchApplication dataApp = new JdbcSrchApplication(indexHome, corpusHome,snapHome);// 数据应用App
    final JdbcSrchEngine jdbc = dataApp.new JdbcSrchEngine();// jdbc风格数据操作界面

}
